package org.wak.character
{
	import org.wak.character.display.AbstractCharacterDisplay;
	import org.wak.character.display.CharacterDisplayFactory;
	import org.wak.character.display.ICharacterDisplayDefinition;
	import org.wak.character.display.XMLCharDisplayDefinition;
	import org.wak.main.AdventureMaster;
	
	/**
	 * This is the manager of Characters and CharactersDisplay entities. 
	 * 
	 */	
	public class CharactersManager
	{
		
		// Input XML with the character display definitions.
		private var mCharDispDefsXML:XML ;
		
		// Input XML with the characters definitions.
		private var mCharsDefsXML:XML ;
		
		// Asociative array of Character Display definitions. CharDisplayId -> IPlayerDisplayDefinition
		private var mCharDisplayDefsArray:Array = null;
		
		// Asociative array of Character Display. CharDisplayId -> AbstractPlayerDisplay 
		private var mCharDisplayArray:Array = null;
		
		// Asociative array of Character Id -> ICharacterDefinition 
		private var mCharactersDefsArray:Array = null ;
		
		// Asociative array of Character Id -> Character
		private var mCharactersArray:Array = null ;
		
		/**
		 * Constructor. 
		 */		
		public function CharactersManager()
		{
			mCharDisplayDefsArray = new Array();
			mCharDisplayArray = new Array(); 
			mCharactersDefsArray = new Array();
			mCharactersArray = new Array ;
			
		}
		
		/**
		 * Loads the Characters's definition, but do not instanciate them .  
		 * @param pXMLCharsDef a XML object with the definition of the Characters.
		 */		
		public function LoadCharsDefinitions( pXMLCharsDef:XML ):void
		{
			mCharsDefsXML = pXMLCharsDef ;
			ExtractCharactersDefinitions( mCharsDefsXML, mCharactersDefsArray );
		}
		
		/**
		 * Loads the CharacterDisplay's definition without instanciate them. 
		 * @param pXMLCharsDispDef an XML with the character displays.
		 * 
		 */		
		public function LoadCharsDisplaysDefinitions( pXMLCharsDispDef:XML ):void
		{
			mCharDispDefsXML = pXMLCharsDispDef ;
			ExtractCharsDisplayDefinitions(mCharDispDefsXML, mCharDisplayDefsArray );
		}
		
		/**
		 * Gets an AdventureCharacter by its id
		 * @param pCharacterId an AdventureCharacter Id.
		 * @return AdventureCharacter of the id received in pCharacterId, returns null if doesn't exist.
		 * 
		 */		
		public function GetCharacter( pCharacterId:String ):AdventureCharacter
		{
			var fReturnChar:AdventureCharacter = null ;
			
			if( mCharactersArray[ pCharacterId ] == null )
			{
				var fCharDef:ICharacterDefinition = mCharactersDefsArray[pCharacterId] as ICharacterDefinition ;
				if( fCharDef == null )
				{
					throw new Error("Unknown character id: "+ pCharacterId);
				}
				else
				{
					mCharactersArray[pCharacterId] = new AdventureCharacter( fCharDef );
					fReturnChar = mCharactersArray[pCharacterId] as AdventureCharacter ;
				} 
			}
			else
			{
				fReturnChar = mCharactersArray[pCharacterId] as AdventureCharacter ;
			}
			
			return fReturnChar ;
			
		}
		
		/**
		 *  Gets an AbstractCharacterDisplay by id
		 * @param pCharDisplayId a CharacterDisplay Id, usually defined in CharsDisplay.xml
		 * @return AbstractCharacterDisplay of the id received in pCharDisplayId, returns null if doesn't exist.
		 * 
		 */		
		public function GetCharacterDisplay( pCharDisplayId:String ):AbstractCharacterDisplay
		{
			var fReturnDisplay:AbstractCharacterDisplay = null ;
			
			if( mCharDisplayArray[ pCharDisplayId ] == null )
			{
				var fCharDispDef:ICharacterDisplayDefinition = mCharDisplayDefsArray[pCharDisplayId] as ICharacterDisplayDefinition ;
				if( fCharDispDef == null )
				{
					throw new Error("Unknown character display id: "+ pCharDisplayId);
				}
				else
				{
					mCharDisplayArray[pCharDisplayId] = CharacterDisplayFactory.CreateCharacterDisplay( fCharDispDef );
					fReturnDisplay = mCharDisplayArray[pCharDisplayId] as AbstractCharacterDisplay ;
				} 
			}
			else
			{
				fReturnDisplay = mCharDisplayArray[pCharDisplayId] as AbstractCharacterDisplay ;
			}
			
			return fReturnDisplay ;
		}
		
		/**
		 * Gets the current player's character. 
		 * @return 
		 * 
		 */		
		public function GetPlayerCharacter():AdventureCharacter
		{
			return this.GetCharacter( AdventureMaster.defaultPlayerCharacterId );
		}
		
		/**
		 * Extracts the CharacterDisplays Definitions from the input XML pDefs to an asociative
		 * Array by Character Display Id. 
		 * @param pDefs XML containing the definitions
		 * @param pDest destination array
		 * 
		 */		
		private function ExtractCharsDisplayDefinitions(pDefs:XML, pDest:Array):void
		{
			var fCharDispDef:ICharacterDisplayDefinition = null;
			for each( var def:XML in pDefs.BmpCharDisplay )
			{
				fCharDispDef = new XMLCharDisplayDefinition( def,true );
				pDest[fCharDispDef.GetCharDisplayId()] = fCharDispDef ;
				//trace("l:"+pDest.length+ " fCharDispDef:"+fCharDispDef);
			}
			
			for each( var defDummy:XML in pDefs.DummyCharDisplay )
			{
				fCharDispDef = new XMLCharDisplayDefinition( defDummy,false, true );
				pDest[fCharDispDef.GetCharDisplayId()] = fCharDispDef ;
				//trace("l:"+pDest.length+ " fCharDispDef:"+fCharDispDef);
			}
		}
		
		/**
		 * Extracts the Character Definitions from the input XML pDefs to an asociative
		 * Array by Character Id -> Character.
		 * @see ICharacterDefinition 
		 * @param pDefs XML containing the definitions
		 * @param pDest destination array
		 * 
		 */		
		private function ExtractCharactersDefinitions(pDefs:XML, pDest:Array):void
		{
			var fCharsDef:ICharacterDefinition = null;
			for each( var def:XML in pDefs.Character )
			{
				fCharsDef = new XMLCharacterDefinition( def );
				pDest[fCharsDef.characterId] = fCharsDef ;
			}
		}
		

	}
}